#include "BaseLogger.h"
#include <time.h>
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#endif
#include <stdarg.h>
#include <malloc.h>

#include <stdint.h>
#include <string.h>
#include "StringUtil.h"

#define DEFAULT_LOG_BUF_LEN 512

BaseLogger::BaseLogger()
{	
	memset(&m_LogStrategy, 0x01, sizeof(m_LogStrategy));
}


BaseLogger::~BaseLogger()
{
}

bool BaseLogger::IsEnable(LOG_LEVEL lv)
{
	return m_LogLevel <= lv;
}

void BaseLogger::SetLevel(LOG_LEVEL lv)
{
	m_LogLevel = lv;
}

const char * BaseLogger::getLoggerName()
{
	return m_strModuleName.c_str();
}

int FmtMsg(char * pBuffer, int len, const char* fmt, ...)
{
	int ret = -1;

	va_list ap;
	va_start(ap, fmt);
#ifdef WIN32
	ret = _snprintf_s(pBuffer, len, _TRUNCATE, fmt, ap);
#else
	ret = snprintf(pBuffer, len, fmt, ap);
#endif
	va_end(ap);

	return ret;
}

struct tm timeToTm(time_t t)
{
#ifdef WIN32
#if _MSC_VER < 1400 //VS2003
	return *localtime(&t);
#else //vs2005->vs2013->
	struct tm tt = { 0 };
	localtime_s(&tt, &t);
	return tt;
#endif
#else //linux
	struct tm tt = { 0 };
	localtime_r(&t, &tt);
	return tt;
#endif
}

bool BaseLogger::Write(LOG_LEVEL lv, const char* fmt, ...)
{
	if (!IsEnable(lv))
	{
		return false;
	}

	char temp[1024] = { 0, };
	va_list args;
	va_start(args, fmt);
	int nLen = vsnprintf(temp, 1024, fmt, args);
	va_end(args);

	LogItem li;
	li.lv = lv;

	int nPos = 0;	
	std::string strHead;
	if (m_LogStrategy.enable_print_datetime)
	{
		time_t timeSec;
		uint32_t mSec;
#ifdef WIN32
		FILETIME ft;
		GetSystemTimeAsFileTime(&ft);
		unsigned long long now = ft.dwHighDateTime;
		now <<= 32;
		now |= ft.dwLowDateTime;
		now /= 10;
		now -= 11644473600000000ULL;
		now /= 1000;
		timeSec = now / 1000;
		mSec = (unsigned int)(now % 1000);
#else
		struct timeval tm;
		gettimeofday(&tm, NULL);
		timeSec = tm.tv_sec;
		mSec = tm.tv_usec / 1000;
#endif
		struct tm tmNow = timeToTm(timeSec);

		strHead += FormatString("%d-%02d-%02d %02d:%02d:%02d.%03d ",
			tmNow.tm_year + 1900, tmNow.tm_mon + 1, tmNow.tm_mday,
			tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec, mSec);
	}

	if (m_LogStrategy.enable_print_module_name)
	{
		strHead += FormatString( "%s ", m_strModuleName.c_str());
	}

	if (m_LogStrategy.enable_print_level)
	{
		strHead += FormatString( "%s ", LOG_STRING[lv]);
	}

	if (m_LogStrategy.enable_print_threadid)
	{
		int threadID = 0;
#ifdef WIN32
		threadID = (int)GetCurrentThreadId();
#else
		threadID = (int)pthread_self();
#endif
		va_list ap;
		va_start(ap, fmt);

		strHead += FormatString("%x ", threadID);
	}

	li.length = strHead.size() + nLen;
	li.buffer = (char*)malloc(li.length+1);
	strcpy(li.buffer, strHead.c_str());
	strcat(li.buffer, temp);
	li.buffer[li.length] = '\0';

	return m_logQueue.push(li);
}

void BaseLogger::ToDevice(bool printAll/* = false*/)
{
	if (printAll)
	{
		LogItem item;
		memset(&item, 0x00,  sizeof(item));
		while (m_logQueue.pop(item))
		{
			if (item.buffer != NULL)
			{
				DoPrint(item);
				free(item.buffer);
			}			
			memset(&item, 0x00, sizeof(item));
		}
	}
	else
	{
		LogItem arItem[100];
		size_t popSize = m_logQueue.pop(arItem);

		for (size_t n = 0; n < popSize; ++n)
		{
			if (arItem[n].buffer != NULL)
			{
				DoPrint(arItem[n]);
				free(arItem[n].buffer);
			}
		}
	}
}

void BaseLogger::DoPrint(LogItem & li)
{

}

void BaseLogger::SetLoggerName(const char * pszName)
{
	m_strModuleName = pszName;
}

void BaseLogger::SetLogStrategy(LogStrategy &ls)
{
	m_LogStrategy = ls;
}
